//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#ifndef __ELASTOS_GRAFIX_PIXEL_FORMAT__
#define __ELASTOS_GRAFIX_PIXEL_FORMAT__

#define DEBUG_COLOR

INLINE UInt32 RGB2Color(
    /* [in] */ UInt8 red,
    /* [in] */ UInt8 green,
    /* [in] */ UInt8 blue)
{
    return ((((UInt32)red) << 16)
        | (((UInt16)green) <<  8)
        | blue | 0xFF000000);
}

INLINE UInt32 ARGB2Color(
    /* [in] */ UInt8 alpha,
    /* [in] */ UInt8 red,
    /* [in] */ UInt8 green,
    /* [in] */ UInt8 blue)
{
    if (0xFF == alpha) {
        return (((UInt32)red) << 16)
            | (((UInt32)green) << 8)
            | ((UInt32)blue) | 0xFF000000;
    }
    else {
        return (((UInt32)alpha) << 24)
            | ((((UInt32)(((alpha * red) + 0x80)
                + (((alpha * red) + 0x80) >> 8))) & 0xFF00) << 8)
            | (((UInt32)(((alpha * green) + 0x80)
                + (((alpha * green) + 0x80) >> 8))) & 0xFF00)
            | (((UInt32)(((alpha * blue) + 0x80)
                + (((alpha * blue) + 0x80) >> 8))) >> 8);
    }
}

INLINE Boolean ColorRegular(
    /* [in] */ UInt32 argb)
{
    UInt8 alpha = argb >> 24;

    if (0xFF == alpha) {
        return TRUE;
    }
    else if (0 == alpha) {
        return 0 == argb ? TRUE : FALSE;
    }
    else {
        UInt16 ra = (argb & 0x00FF0000) >> 8;
        UInt16 ga = argb & 0x0000FF00;
        UInt16 ba = (argb & 0x000000FF) << 8;

        return (ra <= (alpha << 8))
            && (ga <= (alpha << 8)) && (ba <= (alpha << 8));
    }
}

INLINE UInt16 RGB24Format2RGBT555(
    /* [in] */ UInt32 rgb24)
{
    return (((rgb24 & 0x00F80000) >> 9)
        | ((rgb24 & 0x0000F800) >> 6)
        | ((rgb24 & 0x000000F8) >> 3));
}

INLINE UInt16 RGB24Format2RGB565(
    /* [in] */ UInt32 rgb24)
{
    return (((rgb24 & 0x00F80000) >> 8)
        | ((rgb24 & 0x0000FC00) >> 5)
        | ((rgb24 & 0x000000F8) >> 3));
}

INLINE UInt32 RGB24Format2RGBT666(
    /* [in] */ UInt32 rgb24)
{
    return (((rgb24 & 0x00FC0000) >> 6)
        | ((rgb24 & 0x0000FC00) >> 4)
        | ((rgb24 & 0x000000FC) >> 2));
}

INLINE UInt32 FormatNones(
    /* [in] */ UInt32 rgb)
{
    return rgb;
}

inline UInt16 FormatRGB565ToRGBT555(
    /* [in] */ UInt16 rgb565)
{
    return ((rgb565 >> 1) & 0x7FE0) | (rgb565 & 0x001F);
}

INLINE UInt16 FormatRGBT555ToRGB565(
    /* [in] */ UInt16 rgbt555)
{
    return ((rgbt555 << 1 ) & 0xFFE0) | (rgbt555 & 0x001F);
}

INLINE UInt32 FormatRGB565ToRGBT666(
    /* [in] */ UInt16 rgb565)
{
    return ((rgb565 << 2) & 0x3E000)
            | ((rgb565 << 1) & 0xFC0)
            | ((rgb565 << 1) & 0x3E);
}

INLINE UInt32 RGB24BlentRGB24(
    /* [in] */ UInt32 backRGB24,
    /* [in] */ UInt32 frontRGB24,
    /* [in] */ UInt8 alpha = 0xFF)
{
    if (0 == alpha) {
        return backRGB24;
    }
    else if (0xFF == alpha) {
        return frontRGB24;
    }
    else {
        UInt32 s;

        s = ((((frontRGB24 & 0x00FF0000) >> 16) * alpha
            + (((backRGB24 & 0x00FF0000) >> 16) * (0xFF - alpha)))
            & 0x0000FF00) << 8;

        s |= (((frontRGB24 & 0x0000FF00) * alpha
            + ((backRGB24 & 0x0000FF00) * (0xFF - alpha))) & 0x00FF0000) >> 8;

        s |= ((frontRGB24 & 0x000000FF) * alpha
            + ((backRGB24 & 0x000000FF) * (0xFF - alpha))) >> 8;

        return s;
    }
}

INLINE UInt32 RGB24BlentARGB(
    /* [in] */ UInt32 backRGB24,
    /* [in] */ UInt32 frontARGB,
    /* [in] */ UInt8 layerAlpha = 0xFF)
{
    UInt32 alpha = frontARGB >> 24;
    UInt32 s;

    if (0xFF == alpha && 0xFF == layerAlpha) {
        return frontARGB & 0x00FFFFFF;
    }
    else if (0 == alpha || 0 == layerAlpha) {
        return backRGB24;
    }
    else if (0xFF == layerAlpha) {
        s = (((frontARGB & 0x00FF0000) >> 16)
            + ((((backRGB24 & 0x00FF0000) >> 16)
                * (0xFF - alpha) >> 8))) << 16;

        s |= (frontARGB
            + (((backRGB24 & 0x0000FF00) >> 8) * (0xFF - alpha)))& 0x0000FF00;

        s |= (frontARGB & 0x000000FF)
            + (((backRGB24 & 0x000000FF) * (0xFF - alpha)) >> 8);
    }
    else if (0xFF == alpha) {
        s = ((((frontARGB & 0x00FF0000) >> 16) * layerAlpha
            + (((backRGB24 & 0x00FF0000) >> 16 ) * (0xFF - layerAlpha)))
            & 0x0000FF00) << 8;

        s |= (((frontARGB & 0x0000FF00) * layerAlpha
            + ((backRGB24 & 0x0000FF00) * (0xFF - layerAlpha)))
            & 0x00FF0000) >> 8;

        s |= ((frontARGB & 0x000000FF) * layerAlpha
            + ((backRGB24 & 0x000000FF) * (0xFF - layerAlpha))) >> 8;
    }
    else {
        s = ((((frontARGB & 0x00FF0000) >> 16) * layerAlpha
            + (((backRGB24 & 0x00FF0000) >> 16 )
            * (0xFF - ((alpha * layerAlpha) >> 8))) )
            & 0x0000FF00) << 8;

        s |= (((frontARGB & 0x0000FF00) * layerAlpha
            + ((backRGB24 & 0x0000FF00)
            * (0xFF - ((alpha * layerAlpha) >> 8))))
            & 0x00FF0000) >> 8;

        s |= ((frontARGB & 0x000000FF) * layerAlpha
            + ((backRGB24 & 0x000000FF)
            * (0xFF - ((alpha * layerAlpha) >> 8)))) >> 8;
    }

    return s;
}

INLINE UInt32 ARGBBlentRGB24(
    /* [in] */ UInt32 backARGB,
    /* [in] */ UInt32 frontRGB24,
    /* [in] */ UInt8 layerAlpha = 0xFF)
{
    UInt8 alpha = backARGB >> 24;

    if (0xFF == layerAlpha) {
        return frontRGB24 | 0xFF000000;
    }
    else if (0xFF == alpha) {
        return RGB24BlentRGB24(backARGB, frontRGB24, layerAlpha) | 0xFF000000;
    }
    else {
        UInt32 s = RGB24BlentRGB24(backARGB, frontRGB24, layerAlpha);
        alpha = (((alpha + layerAlpha) << 8) - alpha * layerAlpha) >> 8;
#ifdef DEBUG_COLOR
        s |= alpha;
        assert(ColorRegular(s));

        return s;
#else
        return s | alpha;
#endif
    }
}

INLINE UInt32 ARGBBlentARGB(
    /* [in] */ UInt32 backARGB,
    /* [in] */ UInt32 frontARGB,
    /* [in] */ UInt8 layerAlpha = 0xFF)
{
    UInt8 backAlpha = backARGB >> 24;
    UInt8 frontAlpha = frontARGB >> 24;

#ifdef DEBUG_COLOR
    assert(ColorRegular(backARGB) && ColorRegular(frontARGB));
#endif

    if ((0xFF == frontAlpha && 0xFF == layerAlpha) || 0 == backAlpha) {
        return frontARGB;
    }
    else if (0 == frontAlpha || 0 == layerAlpha) {
        return backARGB;
    }
    else if (0xFF == backAlpha) {
        return RGB24BlentARGB(backARGB, frontARGB, layerAlpha) | 0xFF000000;
    }
    else {
        UInt32 s = RGB24BlentARGB(backARGB, frontARGB, layerAlpha);
        UInt32 alpha;

        if (0xFF == layerAlpha) {
            alpha = (((backAlpha + frontAlpha) << 8)
                        - backAlpha * frontAlpha) >> 8;
        }
        else if (0xFF == frontAlpha) {
            alpha = (((backAlpha + layerAlpha) << 8)
                        - backAlpha * layerAlpha) >> 8;
        }
        else {
            UInt8 blentAlpha = frontAlpha * layerAlpha >> 8;
            alpha = (((backAlpha + blentAlpha) << 8)
                        - backAlpha * blentAlpha) >> 8;
        }

#ifdef DEBUG_COLOR
        s |= alpha << 24;
        assert(ColorRegular(s));

        return s;
#else
        return s | (alpha << 24);
#endif
    }
}

#endif
